Skip to content

Add Codex device-code sign-in#1045

Closed
Pedromdsn wants to merge 6 commits intoGitlawb:mainfrom
Pedromdsn:feat/codex-device-code-provider
Closed

Add Codex device-code sign-in#1045
Pedromdsn wants to merge 6 commits intoGitlawb:mainfrom
Pedromdsn:feat/codex-device-code-provider

Conversation

@Pedromdsn
Copy link
Copy Markdown

Summary

  • Add a Codex Device Code provider sign-in option alongside existing Codex OAuth.
  • Reuse existing Codex secure credential storage, profile activation, and runtime routing.
  • Update provider validation hints and ProviderManager preset ordering.

Test plan

  • bun run build
  • bun test src/commands/provider/provider.test.tsx src/components/ProviderManager.test.tsx src/utils/providerValidation.ts
  • bun test src/services/api/providerConfig.codexSecureStorage.test.ts src/services/api/providerConfig.runtimeCodexCredentials.test.ts src/utils/codexCredentials.test.ts
  • Device-code behavior probe for standard parse, malformed response, and access_denied handling

Notes

  • Full bun test has unrelated environment-sensitive failures in StartupScreen.test.ts and sdk-context-isolation.test.ts when Codex/OpenAI env vars are set locally; those tests pass when the Codex env is unset.
  • Repository-wide bun run typecheck currently fails with unrelated baseline errors outside these changed files.

Adds a device-code Codex login path alongside the existing browser OAuth flow while reusing the current Codex credential storage, profile, and runtime routing.
Copilot AI review requested due to automatic review settings May 7, 2026 07:47
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new Codex “device code” sign-in path alongside the existing Codex OAuth flow, reusing the same secure credential storage and Codex runtime activation behavior.

Changes:

  • Introduce a Codex device-code API flow (device-code request + token polling) and a React hook to drive the UI flow and persistence.
  • Add “Codex Device Code” as a selectable option in both ProviderManager and /provider wizard flows.
  • Update provider validation hints and preset ordering expectations.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/utils/providerValidation.ts Updates Codex auth validation hints to mention device-code sign-in.
src/services/api/codexDeviceFlow.ts Adds device-code request/polling implementation for Codex auth.
src/components/useCodexDeviceCodeFlow.ts Adds React hook orchestrating device-code sign-in, browser open, polling, and secure persistence.
src/components/ProviderManager.tsx Adds a new “Codex Device Code” setup screen and preset option.
src/components/ProviderManager.test.tsx Updates preset ordering expectations to include “Codex Device Code”.
src/commands/provider/provider.tsx Adds a new /provider wizard step for Codex device-code sign-in.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/components/ProviderManager.tsx Outdated
Comment on lines 1544 to 1552
if (canUseCodexOAuth) {
options.splice(7, 0, {
value: 'codex-device-code',
label: 'Codex Device Code',
description:
'Sign in with a device code and store Codex credentials securely',
})
options.splice(6, 0, {
value: 'codex-oauth',
Comment on lines +40 to +46
export function useCodexDeviceCodeFlow(options: {
onAuthenticated: (
tokens: CodexOAuthTokens,
persistCredentials: PersistCodexCredentials,
) => void | Promise<void>
deps?: CodexDeviceCodeFlowDependencies
}): CodexDeviceCodeFlowStatus {
Comment on lines +135 to +141
const response = await fetchFn(CODEX_DEVICE_CODE_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body,
})
Comment thread src/services/api/codexDeviceFlow.ts Outdated
Comment on lines +170 to +176
const response = await options.fetchImpl(CODEX_REFRESH_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body,
signal: options.signal,
@kevincodex1
Copy link
Copy Markdown
Contributor

please address copilot's comments

Copy link
Copy Markdown
Collaborator

@jatmn jatmn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Review Response for PR #1045

1. Missing interval is treated as a hard failure

File: src/services/api/codexDeviceFlow.ts

The current device-code response parser rejects otherwise valid successful responses when the provider omits interval. That behavior is inconsistent with the rest of the implementation, which already falls back to a default polling interval of five seconds when interval is absent or non-positive. In practice, this means legitimate device-code sign-in attempts can fail immediately even though the flow already has a safe default.

I recommend accepting responses that omit interval and normalizing that case to the existing five-second fallback.

2. Device-code reauthentication creates redundant Codex profiles

File: src/components/ProviderManager.tsx

The new device-code branch always creates a fresh provider profile instead of reusing the stored Codex-linked profile when one already exists. This differs from the existing Codex OAuth implementation, which updates the prior profile in place. The surrounding credential model still appears to treat Codex secure storage as a single linked login with a single associated profile id, so repeated device-code sign-ins create redundant Codex profiles even though the underlying secure store only tracks one linked profile. The current logout and delete cleanup paths then only follow the most recently stored profile id.

I recommend mirroring the existing OAuth behavior by resolving the stored Codex-linked profile first and updating it when present instead of always creating a new profile.

3. slow_down without an interval does not increase the polling delay

File: src/services/api/codexDeviceFlow.ts

When the token endpoint returns slow_down without an accompanying interval, the polling loop continues at its previous cadence rather than backing off. This can leave the client in a repeated rate-limited state and makes the device-code flow less resilient under real-world server behavior.

I recommend applying a default backoff increase for slow_down even when the response does not provide an explicit interval, such as increasing the current interval by five seconds.

Conclusion

These issues appear reasonably contained, but I recommend addressing them before merge. The first can cause the new sign-in path to fail outright, while the latter two introduce avoidable long-term behavior issues in repeated or rate-limited authentication flows.

@Pedromdsn
Copy link
Copy Markdown
Author

Pedromdsn commented May 7, 2026

Thanks for the review.

I updated the PR to address the feedback:

Updates

  • Kept the Codex sign-in options adjacent in the provider preset list.
  • Added automated coverage for the Codex device-code flow.
  • Added request-level timeout handling for the initial device-code request.
  • Added request-level timeout handling for device-code polling.
  • Fixed the related test typing issue found during validation.

Validation

  • Focused Codex/provider tests pass.
  • Related provider and credential tests pass.
  • bun run build passes.
  • Checked bun run typecheck: it still reports existing repository-wide type errors, but none are from the files changed in this PR.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment on lines +93 to +107
!Number.isFinite(expiresIn) ||
!Number.isFinite(interval)
) {
throw new CodexDeviceFlowError(
'Codex device-code response was missing required fields.',
)
}

return {
deviceCode,
userCode,
verificationUri,
verificationUriComplete,
expiresIn,
interval: interval > 0 ? interval : 5,
Comment on lines +271 to +279
while (Date.now() - startedAt < timeoutMs) {
const result = await pollTokenOnce({
deviceCode,
clientId,
fetchImpl: fetchFn,
signal: options?.signal,
requestTimeoutMs: options?.requestTimeoutMs,
})


void (async () => {
try {
const deviceCode = await requestDeviceCode()
Copy link
Copy Markdown
Collaborator

@jatmn jatmn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up review for PR #1045

Thanks for the updates. I pulled and reviewed the latest PR head (5c686fb6249973b82dc92b8acd79f2cc2bf14dc6). Some earlier feedback was addressed, but the PR is not complete yet.

Intent check

The PR summary says this should add a Codex Device Code provider sign-in option, reuse existing Codex secure credential storage/profile activation/runtime routing, and keep provider UI ordering/validation aligned. The findings below are scoped to that intent: they either break standards-aligned device-code polling, diverge from the existing Codex OAuth profile reuse model, or leave the new ProviderManager path unverified.

Requested changes still outstanding

  1. Missing interval is still treated as a hard failure

    File: src/services/api/codexDeviceFlow.ts

    parseDeviceCodeResponse() still requires Number.isFinite(interval) before accepting the device-code response. If the provider omits interval, the request still throws Codex device-code response was missing required fields. even though the return path already has a fallback of 5. This leaves the prior requested change unresolved.

    This is also against the OAuth 2.0 Device Authorization Grant behavior: interval is optional, and clients use 5 seconds by default when it is absent.

    Please accept an omitted or invalid interval and normalize it to the existing default polling interval.

  2. Device-code reauthentication still creates redundant Codex profiles

    File: src/components/ProviderManager.tsx

    The device-code setup branch still calls addProviderProfile(...) unconditionally. The OAuth branch immediately below it checks the stored Codex-linked profile id and updates that existing profile when present. Device-code sign-in should mirror that behavior so repeated Codex sign-ins do not create duplicate profiles while secure storage only tracks one linked profile id.

    Please reuse/update the existing stored Codex profile when present, then persist credentials with that profile id.

  3. slow_down without an interval still does not increase polling delay

    File: src/services/api/codexDeviceFlow.ts

    pollCodexDeviceToken() only applies the interval + 5 backoff when result.state === 'slow_down' && result.interval. If the token endpoint returns slow_down without an interval, the code falls through and keeps the previous polling cadence.

    Device-code polling expects slow_down to increase the interval by five seconds for this and subsequent requests, even without a server-supplied replacement interval.

    Please increase the polling delay on every slow_down, using the returned interval when present and otherwise applying the default five-second backoff.

Copilot comments status

  • Resolved: Codex OAuth and Codex Device Code are now adjacent in the preset list.
  • Resolved: Hook-level tests were added for useCodexDeviceCodeFlow.
  • Partially addressed: Request-level timeout plumbing was added for the device-code request and polling fetches, but the new timeout tests in src/services/api/codexDeviceFlow.test.ts hang locally when run directly.
  • Still valid: Copilot's latest comment about optional interval is valid.
  • Still valid: Copilot's latest comment about passing the hook abort signal into the initial requestCodexDeviceCode() call is valid. The hook creates an AbortController, but calls requestDeviceCode() with no { signal: controller.signal }, so unmounting during the first request does not cancel it.
  • Still valid / needs decision: Copilot's latest comment about respecting the initial polling interval before the first token request appears valid for device-code semantics. The current loop polls immediately, then sleeps only after a pending response.

Additional review findings

  1. Device-code timeout tests hang

    File: src/services/api/codexDeviceFlow.test.ts

    The two tests that expect a hanging request to abort via requestTimeoutMs: 1 did not complete locally:

    • requestCodexDeviceCode > aborts a hanging request after the per-request timeout
    • pollCodexDeviceToken > aborts a hanging polling request after the per-request timeout

    The other targeted tests in that file pass when filtered individually, and src/components/useCodexDeviceCodeFlow.test.tsx passes. Please adjust the timeout implementation or tests so the new timeout coverage is reliable under Bun.

    This one is primarily a validation/reliability issue. It does not prove the runtime timeout path is broken by itself, but it does mean the PR's newly added timeout coverage is not currently usable as evidence.

  2. ProviderManager has no device-code integration coverage

    File: src/components/ProviderManager.test.tsx

    The PR adds the ProviderManager device-code screen and profile persistence path, but the tests only update preset ordering. There is existing coverage for the OAuth first-run path, but no matching test that exercises Codex Device Code through ProviderManager. This missing coverage is exactly where the duplicate-profile regression lives.

    Please add a ProviderManager test for device-code sign-in that covers profile creation, active profile selection, stored Codex profile linkage, and repeat sign-in reusing the existing Codex profile.

Validation run

  • bun install --frozen-lockfile: passed.
  • bun test src/components/useCodexDeviceCodeFlow.test.tsx: passed, 5 tests.
  • bun test src/services/api/codexDeviceFlow.test.ts: timed out locally.
  • Filtered passing checks from src/services/api/codexDeviceFlow.test.ts: successful parse, successful poll, and caller abort signal tests passed.

@jatmn
Copy link
Copy Markdown
Collaborator

jatmn commented May 8, 2026

@kevincodex1 I'm not sure we should keep down this route for now.
The implementation needs alot of work and is already a sizeable addition to the code base.. for something that even according to openai is still in beta on their side.
Might be better to come back around to this one at a later time when it's more developed by openai as well.

@techbrewboss
Copy link
Copy Markdown
Collaborator

I vote we close this PR. It's incomplete and a beta feature which can be removed without notice.

@kevincodex1
Copy link
Copy Markdown
Contributor

Hi bro @Pedromdsn thank you so much for your time working on this, but since its still a beta feature lets halt for now. will be closing this PR and once its stable already you can reopen and continue working on it.

@kevincodex1 kevincodex1 closed this May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants